package cn.js.sangu.unitStore.service;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.js.sangu.unitStore.common.exception.ServiceException;
import cn.js.sangu.unitStore.dto.FileListDTO;
import cn.js.sangu.unitStore.dto.MsgDTO;
import cn.js.sangu.unitStore.entity.ProcessNode;
import cn.js.sangu.unitStore.entity.ProjectPro;
import cn.js.sangu.unitStore.entity.ProjectProActivity;
import cn.js.sangu.unitStore.mapper.ProjectProMapper;
import cn.js.sangu.unitStore.utils.TokenUtils;
import cn.js.sangu.unitStore.websocket.WebSocketService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ProjectProService extends ServiceImpl<ProjectProMapper, ProjectPro> {

    @Autowired
    ProcessNodeService processNodeService;

    @Autowired
    ProjectProActivityService activityService;

    @Autowired
    WebSocketService webSocketService;

    // 类成员变量，全局使用同一个ObjectMapper实例
    private static final ObjectMapper objectMapper = new ObjectMapper();

    public ProjectPro saveInfo(ProjectPro param) {
        // 参数校验
        Objects.requireNonNull(param, "项目参数不能为空");

        // 构建实体对象
        ProjectPro entity = spliceProjectProInfo(param); // 替换文件列表属性

        // 获取并设置流程模板节点
        Integer templateId = param.getTemplateId();
        Objects.requireNonNull(templateId, "流程模板ID不能为空");

        log.info("正在为项目设置流程模板，模板ID: {}", templateId);
        List<ProcessNode> processNodes = processNodeService.getNodesByTemplateId(templateId);

        if (processNodes == null || processNodes.isEmpty()) {
            log.warn("未找到指定模板的流程节点，模板ID: {}", templateId);
            throw new ServiceException("未找到指定模板的流程节点，请检查模板配置");
        }
        // 将流程节点列表转换为JsonNode类型
        entity.setStepsJson(new ObjectMapper().valueToTree(processNodes));
        log.info("成功为项目设置流程节点，节点数量: {}", processNodes.size());

        // 设置创建人信息
        entity.setCreator(Objects.requireNonNull(TokenUtils.getCurrentUser()).getId());
        if (!super.save(entity)) {
            throw new ServiceException("保存失败！请联系管理员");
        }
        return entity;
    }

    public void updateInfo(ProjectPro param) {
        // 若是流程节点顺序的更新，需要记录
        if (Boolean.TRUE.equals(param.getIsNodeProcess())) {
            this.updateProcessStep(param);
        }

        ProjectPro ProjectPro = spliceProjectProInfo(param);
        ProjectPro.setModifier(Objects.requireNonNull(TokenUtils.getCurrentUser()).getId());
        if (!super.updateById(ProjectPro)) {
            throw new ServiceException("更新失败！请联系管理员");
        }
    }

    public void updateProcessStep(ProjectPro param) {
        // 参数校验
        Objects.requireNonNull(param, "项目参数不能为空");
        Integer currentStep = Objects.requireNonNull(param.getCurrentStep(), "当前步骤号不能为空");
        Integer updateStep = currentStep - 1; // 当前要更新的步骤
        JsonNode stepsJson = Objects.requireNonNull(param.getStepsJson(), "步骤列表不能为空");
        Integer currentUserId = Objects.requireNonNull(TokenUtils.getCurrentUser(), "当前用户未登录").getId();

        try {
            // 解析步骤列表（只解析一次，避免重复解析）
            List<ProcessNode> stepsList = null;
            if (stepsJson.isArray()) {
                stepsList = objectMapper.readValue(
                        stepsJson.toString(),
                        objectMapper.getTypeFactory().constructCollectionType(List.class, ProcessNode.class));
            }

            // 更新当前步骤信息
            ProcessNode nextHandlerNode = null;
            if (stepsList != null && updateStep != null) {
                for (ProcessNode node : stepsList) {
                    // 更新当前步骤信息
                    if (node.getStep().equals(updateStep)) {
                        updateNodeInfo(node, param, currentUserId);
                        // 创建活动记录
                        createProjectActivity(param, node, currentUserId);
                    }
                    // 查找下一个步骤的handler节点
                    if (node.getStep().equals(currentStep)) {
                        nextHandlerNode = node;
                    }
                }

                // 将更新后的步骤列表转换回JsonNode
                stepsJson = objectMapper.valueToTree(stepsList);
            }

            // 保存更新后的项目信息
            param.setStepsJson(stepsJson);
            param.setModifier(currentUserId);

            if (!this.updateById(param)) {
                throw new ServiceException("项目步骤更新失败");
            }

            // 通知下一个节点的负责人
            notifyNextHandler(nextHandlerNode);
        } catch (Exception e) {
            log.error("步骤数据JSON转换或保存失败: {}", e.getMessage());
            throw new ServiceException("步骤数据处理失败: " + e.getMessage());
        }
    }

    /**
     * 更新节点信息
     */
    private void updateNodeInfo(ProcessNode node, ProjectPro param, Integer currentUserId) {
        String description = (param.getConfirmMessage() == null || param.getConfirmMessage().trim().isEmpty())
                ? (node.getDescription() != null ? node.getDescription() : "")
                : param.getConfirmMessage();
        node.setDescription(description);
        node.setStepTime(new Date());
    }

    /**
     * 创建项目活动记录
     */
    private void createProjectActivity(ProjectPro param, ProcessNode node, Integer currentUserId) {
        ProjectProActivity activity = new ProjectProActivity();
        activity.setProId(param.getId()); // 重要：关联项目ID
        activity.setDescription(node.getDescription());
        activity.setStepName(node.getStepName());
        activity.setHandler(node.getHandler());
        activity.setHandlerName(node.getHandlerName());
        activity.setIsPass(param.getIsPass());
        activity.setUserId(currentUserId);
        activityService.save(activity);
    }

    /**
     * 通知下一个节点的负责人
     */
    private void notifyNextHandler(ProcessNode nextNode) {
        if (nextNode == null) {
            log.info("没有找到下一个流程节点，无需发送通知");
            return;
        }

        Integer handlerId = nextNode.getHandler();
        String handlerName = nextNode.getHandlerName();

        if (handlerId != null) {
            try {
                // 创建消息DTO
                MsgDTO msgDTO = new MsgDTO();
                msgDTO.setUid(handlerId.toString());
                msgDTO.setType("syatem");
                msgDTO.setContent("您有新的流程需要处理，请及时查看");
                msgDTO.setFrom("系统通知");

                // 发送通知
                webSocketService.sendMsg(msgDTO);
                log.info("已通知用户[ID: {}，名称: {}]处理流程", handlerId, handlerName);
            } catch (Exception e) {
                log.error("发送流程通知失败: {}", e.getMessage());
                // 不抛出异常，避免影响主流程
            }
        }
    }

    private ProjectPro spliceProjectProInfo(ProjectPro param) {
        List<FileListDTO> fileList = param.getFileList();
        if (null != fileList) {
            param.setFileListJson(new ObjectMapper().valueToTree(fileList));
        }
        return param;
    }
}
